

package com.kimo.shop.listener;

import cn.binarywang.wx.miniapp.bean.WxMaTemplateData;
import cn.binarywang.wx.miniapp.bean.WxMaUniformMessage;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.kimo.shop.bean.enums.RemindType;
import com.kimo.shop.bean.enums.SendType;
import com.kimo.shop.bean.event.SendMessageEvent;
import com.kimo.shop.bean.model.NotifyLog;
import com.kimo.shop.bean.model.NotifyTemplate;
import com.kimo.shop.bean.model.ShopDetail;
import com.kimo.shop.bean.model.User;
import com.kimo.shop.bean.param.NotifyTemplateParam;
import com.kimo.shop.common.config.Constant;
import com.kimo.shop.config.ShopConfig;
import com.kimo.shop.config.WxConfig;
import com.kimo.shop.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.util.*;


/**
 * 统一发送通知的事件
 */
@Slf4j
@Component("sendMessageListener")
@AllArgsConstructor
public class SendMessageListener {

    private final NotifyLogService notifyLogService;
    private final SmsLogService smsLogService;
    private final ShopConfig shopConfig;
    private final WxConfig wxConfig;
    private final NotifyTemplateService notifyTemplateService;

    private final ShopDetailService shopDetailService;


    private final UserService userService;

    @EventListener(SendMessageEvent.class)
    public void sendMsgEvent(SendMessageEvent event) {
        NotifyTemplateParam param = event.getParam();
        if(Objects.isNull(param) || Objects.isNull(param.getUser())){
            return;
        }
        ShopDetail shopDetail = shopDetailService.getById(param.getShopId());
        //获取模板的发送方式，获取商家选择的发送方式
        NotifyTemplate template = notifyTemplateService.getOne(new LambdaQueryWrapper<NotifyTemplate>().eq(NotifyTemplate::getSendType, param.getSendType()));
        if(Objects.isNull(template) || Objects.isNull(shopDetail)){
            return;
        }
        String shopName = Objects.isNull(shopDetail.getShopName()) ?"商城":shopDetail.getShopName();
        // 截取字符串,处理过长商品名称
        if(StrUtil.isNotBlank(param.getProdName())) {
            if (Objects.equals(param.getProdName().substring(param.getProdName().length()-1),StrUtil.SPACE)){
                param.setProdName(param.getProdName().substring(0, Math.min(14, param.getProdName().length() - 1)) + "等商品");
            } else {
                param.setProdName(param.getProdName().substring(0, Math.min(14, param.getProdName().length())) + "等商品");
            }
        }
        param.setGroupCount(Objects.isNull(param.getGroupCount()) ? 0:param.getGroupCount());
        param.setPrice(Objects.isNull(param.getPrice()) ? 0.0:param.getPrice());
        param.setPayType(Objects.isNull(param.getPayType())? 1:param.getPayType());
        param.setDvyTime(Objects.isNull(param.getDvyTime())? new Date():param.getDvyTime());
        // 截取字符串,处理过长名称
        User user = userService.getUserDetail(param.getUser().getUserId());
        String openId = "";
        if(Objects.nonNull(user)) {
            if (CollectionUtils.isNotEmpty(user.getBizUserIdList())) {
                openId = user.getBizUserIdList().get(0);
            }
            param.getUser().setNickName(user.getNickName());
            user.setNickName(user.getNickName().substring(0, Math.min(19, user.getNickName().length() - 1)));
        }
        // 设置平台的消息通知类型
        List<String> notifies = Arrays.asList(template.getTemplateTypes().split(StrUtil.COMMA));
        for (String notify : notifies) {
            template.setSms(StrUtil.equals(notify,"1") ? true:template.getSms());
            template.setSub(StrUtil.equals(notify,"2") ? true:template.getSub());
            template.setApp(StrUtil.equals(notify,"3") ? true:template.getApp());
        }
        // 获取对应map
        Map<String, String> smsParam = getSmsParam(param, shopName);
        String content = replaceContent(smsParam, template.getMessage());
        // 保存的通知集合
        List<NotifyLog> notifyLogs = new ArrayList<>();
        if(template.getSms()) {
            Boolean isRead = smsLogService.sendMsgSms(template,param.getUser().getUserMobile(),smsParam);
            // 替换消息内容
            addNotifyLog(param,content,template,isRead,RemindType.SMS.value(),notifyLogs,param.getOrderNumber());
        }
        if(template.getApp()) {
            addNotifyLog(param,content,template,false, RemindType.MINI.value(),notifyLogs,param.getOrderNumber());
        }
        // 公众号
        if(template.getSub() && StrUtil.isNotBlank(openId)) {
            sendMessage(template,param,openId,shopName);
            addNotifyLog(param,content,template,true, RemindType.MP.value(),notifyLogs,param.getOrderNumber());
        }

        if(CollectionUtils.isNotEmpty(notifyLogs)){
            notifyLogService.saveBatch(notifyLogs);
        }

    }

    /**
     * 发送微信模板信息
     */
    private void sendMessage(NotifyTemplate template, NotifyTemplateParam param, String bizUserId, String shopName) {
        if (param.getUser() == null) {
            return;
        }

        WxMaUniformMessage wxMaUniformMessage = new WxMaUniformMessage();
        wxMaUniformMessage.setMpTemplateMsg(true);
        wxMaUniformMessage.setToUser(bizUserId);
        wxMaUniformMessage.setAppid(shopConfig.getWxMp().getAppId());
        //公众号模板消息所要跳转的小程序
        WxMaUniformMessage.MiniProgram miniProgram = new WxMaUniformMessage.MiniProgram();
        miniProgram.setAppid(shopConfig.getWxMiniApp().getAppId());
        miniProgram.setPagePath("pages/user/user");
        wxMaUniformMessage.setMiniProgram(miniProgram);
        //模板id
        wxMaUniformMessage.setTemplateId(template.getMpCode());
        //模板数据集合
        wxMaUniformMessage.setData(getWxMaTemplateDataList(param,shopName));
        try {
//            wxMaMsgService.sendUniformMsg(wxMaUniformMessage);
            wxConfig.getWxMaService().getMsgService().sendUniformMsg(wxMaUniformMessage);
        } catch (WxErrorException e) {
            //用户未关注公众号，导致的消息发送失败异常
            if (Objects.nonNull(e) && Objects.nonNull(e.getError()) && e.getError().getErrorCode() == 43004){
                log.info("用户（" + param.getUser().getUserId() + "）没有关注公众号，导致消息发送失败");
            }
            //其他异常
            else {
                e.printStackTrace();
            }
        }
    }

    private List<WxMaTemplateData> getWxMaTemplateDataList(NotifyTemplateParam param, String shopName) {
        Map<Integer, List<WxMaTemplateData>> mpMap = new HashMap<>(24);
        List<WxMaTemplateData> dataList = new ArrayList<>();
        String priceStr = param.getPrice() + "元";
        String firstData = "亲爱的" + param.getUser().getNickName() + ",您在商城购买的宝贝还未付款哦！为确保您心爱的宝贝早日启程、顺利抵达，记得尽早付款哦！";
        dataList.add(new WxMaTemplateData("first", firstData));
        dataList.add(new WxMaTemplateData("keyword1",param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2",DateUtil.format(param.getCreateTime(),DatePattern.NORM_DATETIME_PATTERN)));
        dataList.add(new WxMaTemplateData("keyword3",param.getProdName()));
        dataList.add(new WxMaTemplateData("remark","请您及时付款以免订单过期。"));
        mpMap.put(SendType.PRESS_PAY.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "你好，你的订单已付款成功。"));
        dataList.add(new WxMaTemplateData("keyword1",param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2",param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword3",DateUtil.format(new Date(),DatePattern.NORM_DATETIME_PATTERN)));
        dataList.add(new WxMaTemplateData("keyword4",priceStr));
        dataList.add(new WxMaTemplateData("remark","感谢您的支持！"));
        mpMap.put(SendType.PAY_SUCCESS.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "您的退款申请商家已同意"));
        dataList.add(new WxMaTemplateData("keyword1",param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2",param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword3", priceStr));
        dataList.add(new WxMaTemplateData("remark","请及时登录商城，查看退款信息"));
        mpMap.put(SendType.AGREE_REFUND.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "你的退款申请被商家驳回，可与商家协商沟通"));
        dataList.add(new WxMaTemplateData("keyword1",param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2",priceStr));
        dataList.add(new WxMaTemplateData("keyword3",param.getRejectMessage()));
        dataList.add(new WxMaTemplateData("remark","请及时登录商城，查看退款信息"));
        mpMap.put(SendType.REFUSE_REFUND.getValue(),dataList);

        //TODO 暂定
        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "尊敬的客户，您的订单提货成功啦。"));
        dataList.add(new WxMaTemplateData("keyword1",param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword2",priceStr));
        dataList.add(new WxMaTemplateData("keyword3",param.getProdNum().toString()));
        dataList.add(new WxMaTemplateData("keyword4",DateUtil.format(new Date(),DatePattern.NORM_DATETIME_PATTERN)));
        dataList.add(new WxMaTemplateData("remark","感谢您的支持！"));
        mpMap.put(SendType.WRITE_OFF.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "商品已在送往客官的路上"));
        dataList.add(new WxMaTemplateData("keyword1",param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword2","已发货"));
        dataList.add(new WxMaTemplateData("keyword3", param.getDvyName()));
        dataList.add(new WxMaTemplateData("keyword4",param.getDvyFlowId()));
        dataList.add(new WxMaTemplateData("remark",DateUtil.format(new Date(),DatePattern.NORM_DATETIME_PATTERN)));
        mpMap.put(SendType.DELIVERY.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "您参加的拼团因为有效期内未成团，我们将在3个工作日内为您安排自动退款"));
        dataList.add(new WxMaTemplateData("keyword1",param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword2",priceStr));
        dataList.add(new WxMaTemplateData("keyword3", "商城"));
        dataList.add(new WxMaTemplateData("remark","点击进入订单详情页，查看退款进度！"));
        mpMap.put(SendType.GROUP_FAIL.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "恭喜你，拼团已经成功！"));
        dataList.add(new WxMaTemplateData("keyword1",param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword2",priceStr));
        dataList.add(new WxMaTemplateData("remark","请登录商城，查看订单发货信息"));
        mpMap.put(SendType.GROUP_SUCCESS.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "恭喜你，开团已经成功！"));
        dataList.add(new WxMaTemplateData("keyword1",param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword2",priceStr));
        dataList.add(new WxMaTemplateData("remark","快去小程序将参团链接分享给好友进行参团吧！"));
        mpMap.put(SendType.GROUP_START.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "会员升级通知"));
        dataList.add(new WxMaTemplateData("keyword1",param.getLevelName()));
        dataList.add(new WxMaTemplateData("keyword2","成功！"));
        dataList.add(new WxMaTemplateData("remark","商城感谢您的支持！"));
        mpMap.put(SendType.MEMBER.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "您有退款单即将超时，请及时联系商家处理"));
        dataList.add(new WxMaTemplateData("keyword1",shopName));
        dataList.add(new WxMaTemplateData("keyword2","1笔"));
        dataList.add(new WxMaTemplateData("remark","如有疑问请及时与客服联系！"));
        mpMap.put(SendType.REFUND_OUT_TIME.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "亲，物流显示您的订单买家已经确认收货！"));
        dataList.add(new WxMaTemplateData("keyword1", param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2",param.getProdName()));
        dataList.add(new WxMaTemplateData("keyword3","已确认收货"));
        dataList.add(new WxMaTemplateData("remark","如有疑问请及时与客服联系！"));
        mpMap.put(SendType.RECEIPT_ORDER.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "店铺有新的退款申请，请及时处理"));
        dataList.add(new WxMaTemplateData("keyword1",priceStr));
        dataList.add(new WxMaTemplateData("keyword2",param.getRejectMessage()));
        dataList.add(new WxMaTemplateData("keyword3",DateUtil.format(new Date(),DatePattern.NORM_DATETIME_PATTERN)));
        dataList.add(new WxMaTemplateData("keyword4","退款金额原路返回"));
        dataList.add(new WxMaTemplateData("keyword5",param.getRemark()));
        dataList.add(new WxMaTemplateData("remark","请您尽快请登录商家后台操作处理。"));
        mpMap.put(SendType.LAUNCH_REFUND.getValue(),dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMaTemplateData("first", "你的买家已退货，请及时处理"));
        dataList.add(new WxMaTemplateData("keyword1",param.getOrderNumber()));
        dataList.add(new WxMaTemplateData("keyword2",param.getRemark()));
        dataList.add(new WxMaTemplateData("remark","如有疑问请及时与客服联系！"));
        mpMap.put(SendType.RETURN_REFUND.getValue(),dataList);
        return mpMap.get(param.getSendType());
    }

    /**
     * 添加消息
     * @param param 参数
     * @param content 消息内容
     * @param template 模板
     * @param isRead     阅读状态
     * @param value 发送类型
     * @param notifyLogs 消息集合
     */
    private void addNotifyLog(NotifyTemplateParam param, String content, NotifyTemplate template, Boolean isRead, Integer value, List<NotifyLog> notifyLogs,String orderNumber) {
        NotifyLog notifyLog = new NotifyLog();
        notifyLog.setCreateTime(new Date());
        User user = param.getUser();
        notifyLog.setShopId(param.getShopId());
        // 如果大于则为店铺自行接收的消息
        if(param.getSendType() >= 100) {
            notifyLog.setRemindId(param.getShopId().toString());
        }else{
            notifyLog.setRemindId(user.getUserId());
        }
        notifyLog.setSendType(param.getSendType());
        notifyLog.setMessage(content);
        notifyLog.setNickName(user.getNickName());
        notifyLog.setUserMobile(user.getUserMobile());
        notifyLog.setRemindType(value);
        notifyLog.setTemplateId(template.getTemplateId());
        notifyLog.setStatus(isRead ? 1 : 0);
        notifyLog.setOrderNumber(orderNumber);
        notifyLogs.add(notifyLog);

    }


    private Map<String, String> getSmsParam(NotifyTemplateParam param, String shopName) {
        Map<String, String> smsParam = new HashMap<>(20);
        smsParam.put("orderNumber",param.getOrderNumber());
        smsParam.put("shopName",shopName);
        smsParam.put("prodName",param.getProdName());
        if(Objects.isNull(param.getUser())){
            smsParam.put("nickName","用户");
        }else {
            smsParam.put("nickName", param.getUser().getNickName());
        }
        smsParam.put("levelName",param.getLevelName());
        smsParam.put("cancelTime",param.getCancelTime());
        smsParam.put("price",String.valueOf(param.getPrice()));
        smsParam.put("dvyFlowId",param.getDvyFlowId());
        smsParam.put("stationName",param.getStationName());
        smsParam.put("dvyName",param.getDvyName());
        smsParam.put("dvyTime",DateUtil.format(param.getDvyTime(),
                DatePattern.NORM_DATETIME_PATTERN));
        smsParam.put("day", String.valueOf(Constant.MAX_REFUND_APPLY_TIME));
        smsParam.put("hour", param.getHour().toString());
        smsParam.put("date",DateUtil.format(param.getDvyTime(),
                DatePattern.NORM_DATETIME_PATTERN));
        return smsParam;
    }



    /**
     * 短信内容替换
     * @param maps 替换内容
     */
    private String replaceContent(Map<String, String> maps,String content) {
        for (Map.Entry<String, String> element : maps.entrySet()) {
            if(StrUtil.isNotBlank(element.getValue())) {
                content = content.replace("${" + element.getKey() + "}", element.getValue());
            }
        }
        return content;
    }

}
